package com.ttsf.compiler

import com.google.auto.service.AutoService
import com.squareup.javapoet.*
import com.ttsf.api.Parameter
import com.ttsf.compiler.utils.ProcessorConfig
import com.ttsf.compiler.utils.ProcessorUtils
import javax.annotation.processing.*
import javax.lang.model.SourceVersion
import javax.lang.model.element.Element
import javax.lang.model.element.Modifier
import javax.lang.model.element.TypeElement
import javax.lang.model.util.Elements
import javax.lang.model.util.Types
import javax.tools.Diagnostic

/**
 * @Created by BoZ At 11/22/20
 * @Description:
 */

@AutoService(value = [Processor::class])
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes(value = ["com.ttsf.api.Parameter"])
class ParameterProcessor : AbstractProcessor() {

    private var elementUtils: Elements? = null
    private var typeUtils: Types? = null
    private var messager: Messager? = null
    private var filer: Filer? = null

    // 临时map存储，用来存放被@Parameter注解的属性集合，生成类文件时遍历
    // key:类节点, value:被@Parameter注解的属性集合
    private val tempParameterMap: MutableMap<TypeElement, ArrayList<Element>> = mutableMapOf()


    override fun init(processingEnv: ProcessingEnvironment?) {
        super.init(processingEnv)

        elementUtils = processingEnv?.elementUtils
        typeUtils = processingEnv?.typeUtils
        messager = processingEnv?.messager
        filer = processingEnv?.filer
    }

    override fun process(
        set: MutableSet<out TypeElement>?,
        roundEnvironment: RoundEnvironment?
    ): Boolean {
        // 由于返回了 false 就不需要一下代码了
//        if (set.isEmpty(set)){
//            return false
//        }

        if (!ProcessorUtils.isEmpty(set)) {


            val elements = roundEnvironment?.getElementsAnnotatedWith(Parameter::class.java)
            // element == name， sex,  age
            elements?.forEach {
                // 字段节点的上一个节点 类节点==Key
                // 注解在属性的上面，属性节点父节点 是 类节点
                val enclosingElement: TypeElement = it.enclosingElement as TypeElement
                if (tempParameterMap.containsKey(enclosingElement)) {
                    tempParameterMap[enclosingElement]?.add(it)
                } else {
                    // 没有key Personal_MainActivity
                    val fields: ArrayList<Element> = ArrayList()
                    fields.add(it)
                    tempParameterMap[enclosingElement] = fields
                }// for end  缓存 tempParameterMap有值了

                if (tempParameterMap.isEmpty()) return true

                val activityType = elementUtils?.getTypeElement(ProcessorConfig.ACTIVITY_PACKAGE)
                val parameterType =
                    elementUtils?.getTypeElement(ProcessorConfig.AROUTER_AIP_PARAMETER_GET)

                // 生成方法

                val parameterSpec = ParameterSpec.builder(
                    TypeName.OBJECT,
                    ProcessorConfig.PARAMETER_NAME
                ).build()
                // 循环遍历 缓存tempParameterMap
                // 可能很多地方都使用了 @Parameter注解，那么就需要去遍历 仓库
                tempParameterMap.forEach {
                    // key：   Personal_MainActivity
                    // value： [name,sex,age]

                    // key：   Personal_MainActivity
                    // value： [name,sex,age]
                    val typeElement: TypeElement = it.key

                    if (!typeUtils?.isSubtype(typeElement.asType(), activityType?.asType())!!) {
                        throw RuntimeException("@Parameter注解目前仅限用于Activity类之上")
                    }

                    val className = ClassName.get(typeElement)

                    val factory = ParameterFactory.Builder(parameterSpec).setClassName(className)
                        .setMessager(messager)
                        .build()

                    factory.addFirstStatement()

                    it.value.forEach { value ->
                        factory.buildStatement(value)
                    }


                    // 最终生成的类文件名（类名$$Parameter） 例如：Personal_MainActivity$$Parameter

                    // 最终生成的类文件名（类名$$Parameter） 例如：Personal_MainActivity$$Parameter
                    val finalClassName: String =
                        "${typeElement.simpleName}${ProcessorConfig.PARAMETER_FILE_NAME}"
                    messager!!.printMessage(
                        Diagnostic.Kind.NOTE, "APT生成获取参数类文件：" +
                                className.packageName() + "." + finalClassName
                    )

                    // 开始生成文件，例如：PersonalMainActivity$$Parameter

                    // 开始生成文件，例如：PersonalMainActivity$$Parameter
                    try {
                        JavaFile.builder(
                            className.packageName(),  // 包名
                            TypeSpec.classBuilder(finalClassName) // 类名
                                .addSuperinterface(ClassName.get(parameterType)) //  implements ParameterGet 实现ParameterLoad接口
                                .addModifiers(Modifier.PUBLIC) // public修饰符
                                .addMethod(factory.build()) // 方法的构建（方法参数 + 方法体）
                                .build()
                        ) // 类构建完成
                            .build() // JavaFile构建完成
                            .writeTo(filer) // 文件生成器开始生成类文件
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }


                }


            }


        }

// return false 只执行一遍不用在检测一遍  true是执行一次  检测一遍
        return false
    }


}